import pandas as pd
pd.set_option('display.expand_frame_repr', False)
import matplotlib
import matplotlib.pyplot as plt
font = {'size' : 20}
matplotlib.rc('font', **font)
import seaborn as sns
from pylab import rcParams
rcParams["figure.figsize"] = 30,16
from collections import OrderedDict
import datetime as dt
from datetime import date
from datetime import datetime
import sklearn
from sklearn import metrics
from sklearn.model_selection import KFold
from sklearn.preprocessing import MinMaxScaler
import joblib
import numpy as np
np.random.seed(0)
import scipy
import datetime as dt
from datetime import date
import tensorflow
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, LSTM, Activation, InputLayer
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.regularizers import l2
import warnings
warnings.filterwarnings("ignore")
import sys
sys.path.insert(0, "../")
import functions
#Funktion für RMSE erstellen
from keras import backend as K
def root_mean_squared_error(y_true, y_pred):
return K.sqrt(K.mean(K.square(y_pred - y_true)))
Es wird zunächst ein simples Netz entwickelt. Das Netz besteht aus einer LSTM-Schicht á 32 Neuronen, die mittels Tanh aktiviert werden. Das Training erfolgt über 50 Epochen mit einer Batchgröße von 16 und einer Lernrate von 0,001. Die Fensterlänge wird initial auf 14 festgelegt.
#Hyperparameter
epochs = 50
batch_size = 16
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=32, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.001)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 30000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.41 1.92 1.98 2 2.52 1.95 1.93 3 2.56 1.79 1.82 4 2.33 1.79 2.05 5 2.56 1.85 1.84 Average 2.48 1.86 1.92
Das Modell lernt sehr schnell an. In den frühen Epochen wird die Verlustfunktion sehr stark reduziert, ab etwa der 20. Epoche ist der Nutzen je Epoche bereits sehr gering. Ab etwa der 40. Epoche beginnt die Konvergenz des Modells. Das Netz lern sogar so schnell an, dass die Verlustfunktion bei den Validierungsdaten in den ersten 10 Epochen etwas niedriger ist als bei den Trainingsdaten. Ein derartiger Verlauf der Lernkurve lässt auf eine zu hohe Lernrate hindeuten.
Das Modell erreicht auf den Testdaten einen MAPE von etwa 2,39%, im Vergleich dazu wird auf den Trainingsdaten 1,89% erreicht. Neben der möglicherweise zu hohen Lernrate liegt also außerdem eine leichte Überanpassung vor.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/50 137/137 [==============================] - 2s 4ms/step - loss: 0.1664 Epoch 2/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0676 Epoch 3/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0607 Epoch 4/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0561 Epoch 5/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0525 Epoch 6/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0507 Epoch 7/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0488 Epoch 8/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0471 Epoch 9/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0462 Epoch 10/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0447 Epoch 11/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0440 Epoch 12/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0430 Epoch 13/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0413 Epoch 14/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0413 Epoch 15/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0402 Epoch 16/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0415 Epoch 17/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0390 Epoch 18/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0403 Epoch 19/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0388 Epoch 20/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0378 Epoch 21/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0379 Epoch 22/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0387 Epoch 23/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0381 Epoch 24/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0367 Epoch 25/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0363 Epoch 26/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0361 Epoch 27/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0361 Epoch 28/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0359 Epoch 29/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0350 Epoch 30/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0347 Epoch 31/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0360 Epoch 32/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0348 Epoch 33/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0348 Epoch 34/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0339 Epoch 35/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0339 Epoch 36/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0341 Epoch 37/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0341 Epoch 38/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0331 Epoch 39/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0336 Epoch 40/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0339 Epoch 41/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0328 Epoch 42/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0331 Epoch 43/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0331 Epoch 44/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0326 Epoch 45/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0336 Epoch 46/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0321 Epoch 47/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0325 Epoch 48/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0329 Epoch 49/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0319 Epoch 50/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0319
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.96 0.97
MAE 3957.0 3010.0
MSE 28446877.0 20092047.0
RMSE 5334.0 4482.0
MAPE 2.39 % 1.89 %
Es wird also zunächst versucht, die Lernrate etwas zu senken. Dafür wird die Lernrate von 0,001 auf 0,0005 gesenkt.
#Hyperparameter
epochs = 50
batch_size = 16
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=32, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0005)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 30000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.55 2.10 2.17 2 2.66 1.94 1.93 3 2.45 1.92 1.98 4 2.59 2.03 2.21 5 2.30 2.05 1.95 Average 2.51 2.01 2.05
Das Netz verhält sich beim Training mit der etwas niedrigeren Lernrate immer noch ähnlich, allerdings setzt die Konvergenz scheinbar etwas später ein. Die Anzahl an Epochen sollte bei einer geringeren Lernrate also erhöht werden.
Das Modell hat sich trotzdem insgesamt etwas verbessert. Der MAPE fällt bei den Testdaten auf 2,2%, steigt dafür aber auf den Trainingsdaten auf 2,04%. Die Überanpassung wurde also bereits teilweise behoben.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/50 137/137 [==============================] - 2s 4ms/step - loss: 0.2612 Epoch 2/50 137/137 [==============================] - 1s 4ms/step - loss: 0.1292 Epoch 3/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0795 Epoch 4/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0691 Epoch 5/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0644 Epoch 6/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0623 Epoch 7/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0578 Epoch 8/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0548 Epoch 9/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0554 Epoch 10/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0522 Epoch 11/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0499 Epoch 12/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0497 Epoch 13/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0494 Epoch 14/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0474 Epoch 15/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0471 Epoch 16/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0457 Epoch 17/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0473 Epoch 18/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0461 Epoch 19/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0445 Epoch 20/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0437 Epoch 21/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0431 Epoch 22/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0429 Epoch 23/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0415 Epoch 24/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0416 Epoch 25/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0405 Epoch 26/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0407 Epoch 27/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0394 Epoch 28/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0396 Epoch 29/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0382 Epoch 30/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0376 Epoch 31/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0380 Epoch 32/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0375 Epoch 33/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0374 Epoch 34/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0371 Epoch 35/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0365 Epoch 36/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0375 Epoch 37/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0365 Epoch 38/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0356 Epoch 39/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0360 Epoch 40/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0352 Epoch 41/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0352 Epoch 42/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0345 Epoch 43/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0355 Epoch 44/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0343 Epoch 45/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0347 Epoch 46/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0352 Epoch 47/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0342 Epoch 48/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0343 Epoch 49/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0334 Epoch 50/50 137/137 [==============================] - 1s 4ms/step - loss: 0.0338
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.96 0.97
MAE 3737.0 3201.0
MSE 24844483.0 21776703.0
RMSE 4984.0 4667.0
MAPE 2.2 % 2.04 %
Da einer verringerte Lernrate das Modell verbessert und auch die Überanpassung vermindert, wird eine noch niedrigere Lernrate ausprobiert. Sie wird von 0,0005 auf 0,0001 gesenkt.
#Hyperparameter
epochs = 75
batch_size = 16
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=32, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0001)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 50000)
Testdaten Trainingsdaten Validierungsdaten Split 1 3.09 2.99 3.11 2 2.79 2.83 2.75 3 2.49 2.59 2.62 4 2.63 2.72 2.99 5 2.53 2.58 2.47 Average 2.71 2.74 2.79
Das Netz lernt zu Beginn nun sehr viel langsamer, die Konvergenz setzt erwartungsgemäß erst nach mehr Epochen ein. Das Training sollte also möglicherweise etwas verlängert werden. Es scheint zunächst nicht zu Überanpassungen zu kommen. Allerdings sind die Verlustfunktionen etwas höher.
Das Modell hat sich durch die sehr niedrigere Lernrate erheblich verschlechtert. Der Abstand des MAPE auf Trainings- und Testdaten hat sich verringert, die Überanpassung nimmt also weiter ab. Allerdings scheint es eher zu einer Unteranpassung zu kommen, da das Modell sehr schlecht abschneidet.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/75 137/137 [==============================] - 2s 4ms/step - loss: 0.3093 Epoch 2/75 137/137 [==============================] - 1s 4ms/step - loss: 0.1910 Epoch 3/75 137/137 [==============================] - 1s 4ms/step - loss: 0.1724 Epoch 4/75 137/137 [==============================] - 1s 4ms/step - loss: 0.1584 Epoch 5/75 137/137 [==============================] - 1s 5ms/step - loss: 0.1414 Epoch 6/75 137/137 [==============================] - 1s 4ms/step - loss: 0.1237 Epoch 7/75 137/137 [==============================] - 1s 4ms/step - loss: 0.1058 Epoch 8/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0892 Epoch 9/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0789 Epoch 10/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0723 Epoch 11/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0701 Epoch 12/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0686 Epoch 13/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0665 Epoch 14/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0664 Epoch 15/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0649 Epoch 16/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0639 Epoch 17/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0629 Epoch 18/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0620 Epoch 19/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0610 Epoch 20/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0596 Epoch 21/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0598 Epoch 22/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0582 Epoch 23/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0580 Epoch 24/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0572 Epoch 25/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0576 Epoch 26/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0559 Epoch 27/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0554 Epoch 28/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0549 Epoch 29/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0548 Epoch 30/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0541 Epoch 31/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0535 Epoch 32/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0524 Epoch 33/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0524 Epoch 34/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0522 Epoch 35/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0516 Epoch 36/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0509 Epoch 37/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0508 Epoch 38/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0507 Epoch 39/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0499 Epoch 40/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0495 Epoch 41/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0496 Epoch 42/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0493 Epoch 43/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0489 Epoch 44/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0485 Epoch 45/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0487 Epoch 46/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0484 Epoch 47/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0479 Epoch 48/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0479 Epoch 49/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0471 Epoch 50/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0471 Epoch 51/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0475 Epoch 52/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0470 Epoch 53/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0465 Epoch 54/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0468 Epoch 55/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0459 Epoch 56/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0458 Epoch 57/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0454 Epoch 58/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0460 Epoch 59/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0457 Epoch 60/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0453 Epoch 61/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0449 Epoch 62/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0451 Epoch 63/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0450 Epoch 64/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0441 Epoch 65/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0446 Epoch 66/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0444 Epoch 67/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0446 Epoch 68/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0438 Epoch 69/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0442 Epoch 70/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0438 Epoch 71/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0435 Epoch 72/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0438 Epoch 73/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0433 Epoch 74/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0435 Epoch 75/75 137/137 [==============================] - 1s 4ms/step - loss: 0.0433
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.94 0.95
MAE 4602.0 4097.0
MSE 38403103.0 33892941.0
RMSE 6197.0 5822.0
MAPE 2.7 % 2.57 %
Die Lernrate wird wieder auf 0,005 festgelegt, da sich hier gute Ergebnisse erzielen ließen. Im nächsten Verusch werden die Batches von 16 auf 32 erhöht, um sicherzustellen, dass die Verlustfunktion nicht in einem lokalen Minimum hängen bleibt.
#Hyperparameter
epochs = 75
batch_size = 32
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=32, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0005)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 30000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.58 2.17 2.20 2 2.42 2.04 1.98 3 2.36 2.13 2.17 4 2.70 2.19 2.44 5 2.29 2.30 2.17 Average 2.47 2.17 2.19
Wie schon bei LSTM-2 lernt das Modell sehr schnell und die Konvergenz setzt etwas früher ein.
Im Vergleich zu LSTM-2 lassen sich der MAPE auf den Trainings- und Testdaten jedoch nicht wirklich verbessern. Bei den Testdaten setzt sogar eine leichte Verschlechterung ein, was auf eine leichte Überanpassung deuten könnte.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/75 69/69 [==============================] - 2s 4ms/step - loss: 0.3148 Epoch 2/75 69/69 [==============================] - 0s 4ms/step - loss: 0.1612 Epoch 3/75 69/69 [==============================] - 0s 4ms/step - loss: 0.1234 Epoch 4/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0806 Epoch 5/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0671 Epoch 6/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0631 Epoch 7/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0607 Epoch 8/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0606 Epoch 9/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0573 Epoch 10/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0560 Epoch 11/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0549 Epoch 12/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0535 Epoch 13/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0539 Epoch 14/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0523 Epoch 15/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0508 Epoch 16/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0492 Epoch 17/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0493 Epoch 18/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0485 Epoch 19/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0481 Epoch 20/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0475 Epoch 21/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0466 Epoch 22/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0463 Epoch 23/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0451 Epoch 24/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0444 Epoch 25/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0443 Epoch 26/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0440 Epoch 27/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0437 Epoch 28/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0438 Epoch 29/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0430 Epoch 30/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0434 Epoch 31/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0415 Epoch 32/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0418 Epoch 33/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0412 Epoch 34/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0416 Epoch 35/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0410 Epoch 36/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0423 Epoch 37/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0407 Epoch 38/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0409 Epoch 39/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0398 Epoch 40/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0404 Epoch 41/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0399 Epoch 42/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0403 Epoch 43/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0393 Epoch 44/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0396 Epoch 45/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0401 Epoch 46/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0399 Epoch 47/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0388 Epoch 48/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0398 Epoch 49/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0388 Epoch 50/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0380 Epoch 51/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0380 Epoch 52/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0393 Epoch 53/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0374 Epoch 54/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0383 Epoch 55/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0376 Epoch 56/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0377 Epoch 57/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0376 Epoch 58/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0376 Epoch 59/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0377 Epoch 60/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0367 Epoch 61/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0369 Epoch 62/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0360 Epoch 63/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0364 Epoch 64/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0362 Epoch 65/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0366 Epoch 66/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0356 Epoch 67/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0366 Epoch 68/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0360 Epoch 69/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0360 Epoch 70/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0366 Epoch 71/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0366 Epoch 72/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0363 Epoch 73/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0360 Epoch 74/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0358 Epoch 75/75 69/69 [==============================] - 0s 4ms/step - loss: 0.0359
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.96 0.97
MAE 4060.0 3212.0
MSE 29637490.0 22783486.0
RMSE 5444.0 4773.0
MAPE 2.42 % 2.03 %
Es wird nun versucht, das Training mit einer kleineren Batchgröße á 8 und etwas mehr Epochen als bei LSTM-2 zu verbessern.
#Hyperparameter
epochs = 100
batch_size = 8
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=32, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0005)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 20000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.35 1.59 1.72 2 2.60 1.67 1.74 3 2.16 1.69 1.78 4 2.43 1.61 1.87 5 2.15 1.85 1.87 Average 2.34 1.68 1.80
Wie schon bei LSTM-2 lernt das Modell sehr schnell und die Konvergenz setzt etwas früher ein. Eine Verbesserung bei der Verlustfunktion ist zunächst nicht zu erkennen. Allerdings setzt die Konvergenz erst sehr spät ein, es könnten also gegebenenfalls mehr Epochen notwendig sein. Davon soll allerdings zunächst abgesehen werden, da es hierdurch zu stärkeren Überanpassungen kommt.
Der MAPE hat sich geringfügig verbessert, aher werden zunächst weiter 8er Batches verwendet. Stattdessen soll die LSTM-Schicht durch weitere Neuronen ergänzt werden, um mehr Potenzial zu schaffen.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/100 273/273 [==============================] - 2s 4ms/step - loss: 0.1592 Epoch 2/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0690 Epoch 3/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0602 Epoch 4/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0565 Epoch 5/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0546 Epoch 6/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0505 Epoch 7/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0477 Epoch 8/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0477 Epoch 9/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0458 Epoch 10/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0438 Epoch 11/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0428 Epoch 12/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0424 Epoch 13/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0414 Epoch 14/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0400 Epoch 15/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0392 Epoch 16/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0386 Epoch 17/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0387 Epoch 18/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0390 Epoch 19/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0393 Epoch 20/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0375 Epoch 21/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0369 Epoch 22/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0360 Epoch 23/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0363 Epoch 24/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0358 Epoch 25/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0353 Epoch 26/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0350 Epoch 27/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0344 Epoch 28/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0348 Epoch 29/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0350 Epoch 30/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0339 Epoch 31/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0339 Epoch 32/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0339 Epoch 33/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0335 Epoch 34/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0334 Epoch 35/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0330 Epoch 36/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0322 Epoch 37/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0331 Epoch 38/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0332 Epoch 39/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0326 Epoch 40/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0328 Epoch 41/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0325 Epoch 42/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0321 Epoch 43/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0324 Epoch 44/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0325 Epoch 45/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0318 Epoch 46/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0320 Epoch 47/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0321 Epoch 48/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0309 Epoch 49/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0312 Epoch 50/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0314 Epoch 51/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0312 Epoch 52/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0308 Epoch 53/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0312 Epoch 54/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0306 Epoch 55/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0307 Epoch 56/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0304 Epoch 57/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0311 Epoch 58/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0299 Epoch 59/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0300 Epoch 60/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0304 Epoch 61/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0299 Epoch 62/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0305 Epoch 63/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0300 Epoch 64/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0299 Epoch 65/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0300 Epoch 66/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0296 Epoch 67/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0295 Epoch 68/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0292 Epoch 69/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0295 Epoch 70/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0288 Epoch 71/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0290 Epoch 72/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0292 Epoch 73/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0288 Epoch 74/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0290 Epoch 75/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0291 Epoch 76/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0294 Epoch 77/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0288 Epoch 78/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0287 Epoch 79/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0286 Epoch 80/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0282 Epoch 81/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0286 Epoch 82/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0287 Epoch 83/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0284 Epoch 84/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0278 Epoch 85/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0280 Epoch 86/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0281 Epoch 87/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0283 Epoch 88/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0281 Epoch 89/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0281 Epoch 90/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0277 Epoch 91/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0279 Epoch 92/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0276 Epoch 93/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0277 Epoch 94/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0275 Epoch 95/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0276 Epoch 96/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0273 Epoch 97/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0279 Epoch 98/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0274 Epoch 99/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0273 Epoch 100/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0275
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.96 0.98
MAE 3932.0 2640.0
MSE 26749742.0 14539764.0
RMSE 5172.0 3813.0
MAPE 2.36 % 1.65 %
Die LSTM-Schicht wird durch weitere Neuronen ergänzt, um mehr Potenzial zu erschließen. Dafür werden statt 32 nun 64 Neuronen in die Schicht eingefügt.
#Hyperparameter
epochs = 100
batch_size = 8
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=64, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0005)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 20000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.35 1.75 1.93 2 2.52 1.50 1.70 3 2.47 1.44 1.65 4 2.39 1.51 1.86 5 2.38 1.53 1.60 Average 2.42 1.55 1.75
Das Netz lern weiterhin sehr schnell an, die Konvergenz beginnt ab etwa der 80 Epoche. Allerdings konvergiert die Lernkurve nur bei den Testdaten. Bei den Trainingsdaten führen mehr Epochen zu einer Überanpassung an die Trainingsdaten.
Der MAPE sinkt auf den Testdaten auf etwa 2,2%, auf den Trainingsdaten allerdings auf 1,4%. Hier deutet sich also ebenfalls eine Überanpassung an.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/100 273/273 [==============================] - 2s 4ms/step - loss: 0.1658 Epoch 2/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0642 Epoch 3/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0575 Epoch 4/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0517 Epoch 5/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0505 Epoch 6/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0472 Epoch 7/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0459 Epoch 8/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0454 Epoch 9/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0436 Epoch 10/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0420 Epoch 11/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0417 Epoch 12/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0396 Epoch 13/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0386 Epoch 14/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0375 Epoch 15/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0378 Epoch 16/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0368 Epoch 17/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0365 Epoch 18/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0365 Epoch 19/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0346 Epoch 20/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0357 Epoch 21/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0343 Epoch 22/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0337 Epoch 23/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0342 Epoch 24/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0337 Epoch 25/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0332 Epoch 26/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0328 Epoch 27/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0328 Epoch 28/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0322 Epoch 29/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0331 Epoch 30/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0324 Epoch 31/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0321 Epoch 32/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0326 Epoch 33/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0318 Epoch 34/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0319 Epoch 35/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0317 Epoch 36/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0319 Epoch 37/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0319 Epoch 38/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0313 Epoch 39/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0308 Epoch 40/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0314 Epoch 41/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0305 Epoch 42/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0309 Epoch 43/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0308 Epoch 44/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0303 Epoch 45/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0306 Epoch 46/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0301 Epoch 47/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0299 Epoch 48/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0300 Epoch 49/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0302 Epoch 50/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0299 Epoch 51/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0297 Epoch 52/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0301 Epoch 53/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0296 Epoch 54/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0293 Epoch 55/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0287 Epoch 56/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0292 Epoch 57/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0291 Epoch 58/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0293 Epoch 59/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0286 Epoch 60/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0291 Epoch 61/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0287 Epoch 62/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0288 Epoch 63/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0284 Epoch 64/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0285 Epoch 65/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0280 Epoch 66/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0283 Epoch 67/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0276 Epoch 68/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0275 Epoch 69/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0278 Epoch 70/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0278 Epoch 71/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0273 Epoch 72/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0265 Epoch 73/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0272 Epoch 74/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0269 Epoch 75/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0268 Epoch 76/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0262 Epoch 77/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0266 Epoch 78/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0263 Epoch 79/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0258 Epoch 80/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0264 Epoch 81/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0261 Epoch 82/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0260 Epoch 83/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0261 Epoch 84/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0262 Epoch 85/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0255 Epoch 86/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0259 Epoch 87/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0256 Epoch 88/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0261 Epoch 89/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0252A: 0s - loss: Epoch 90/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0249 Epoch 91/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0251 Epoch 92/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0246 Epoch 93/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0252 Epoch 94/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0246 Epoch 95/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0254 Epoch 96/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0245 Epoch 97/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0248 Epoch 98/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0245 Epoch 99/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0242 Epoch 100/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0242
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.97 0.98
MAE 3642.0 2243.0
MSE 23042014.0 11301258.0
RMSE 4800.0 3362.0
MAPE 2.19 % 1.4 %
Die LSTM-Schicht wird durch weitere Neuronen ergänzt, um mehr Potenzial zu erschließen. Dafür werden statt 64 nun 128 Neuronen in die Schicht eingefügt.
#Hyperparameter
epochs = 100
batch_size = 8
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=128, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0005)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 20000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.20 1.56 1.83 2 2.33 1.51 1.77 3 2.01 1.44 1.72 4 2.36 1.49 1.89 5 2.05 1.59 1.74 Average 2.19 1.52 1.79
Die Lernkurve zeigt, dass die Überanpassung ab etwa der 60. Epoche einsetzt.
Während der Kreuzvalidierungen lässt sich zwar stellenweise der MAPE auf den Trainingsdaten reduzieren, aber abgesehen davon führen die zusätzlichen Neuronen zu keiner Verbesserung. Von einer Erweiterung auf 128 Neuronen kann also abgesehen werden.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/100 273/273 [==============================] - 3s 6ms/step - loss: 0.1306 Epoch 2/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0634 Epoch 3/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0545 Epoch 4/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0516 Epoch 5/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0477 Epoch 6/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0459 Epoch 7/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0444 Epoch 8/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0432 Epoch 9/100 273/273 [==============================] - 2s 7ms/step - loss: 0.0406 Epoch 10/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0390 Epoch 11/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0381 Epoch 12/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0373 Epoch 13/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0356 Epoch 14/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0350 Epoch 15/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0356 Epoch 16/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0355 Epoch 17/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0337 Epoch 18/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0335 Epoch 19/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0335 Epoch 20/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0337 Epoch 21/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0331 Epoch 22/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0325 Epoch 23/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0323 Epoch 24/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0318 Epoch 25/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0323 Epoch 26/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0328 Epoch 27/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0317 Epoch 28/100 273/273 [==============================] - 2s 7ms/step - loss: 0.0323 Epoch 29/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0317 Epoch 30/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0308 Epoch 31/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0313 Epoch 32/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0306 Epoch 33/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0311 Epoch 34/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0309 Epoch 35/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0311 Epoch 36/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0300 Epoch 37/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0303 Epoch 38/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0297 Epoch 39/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0304 Epoch 40/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0305 Epoch 41/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0294 Epoch 42/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0289 Epoch 43/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0292 Epoch 44/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0289 Epoch 45/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0288 Epoch 46/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0286 Epoch 47/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0281 Epoch 48/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0281 Epoch 49/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0277 Epoch 50/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0279 Epoch 51/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0276 Epoch 52/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0274 Epoch 53/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0274 Epoch 54/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0270 Epoch 55/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0278 Epoch 56/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0275 Epoch 57/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0273 Epoch 58/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0273 Epoch 59/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0267 Epoch 60/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0264 Epoch 61/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0269 Epoch 62/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0269 Epoch 63/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0265 Epoch 64/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0260 Epoch 65/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0273 Epoch 66/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0270 Epoch 67/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0262 Epoch 68/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0260 Epoch 69/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0252 Epoch 70/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0252 Epoch 71/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0255 Epoch 72/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0253 Epoch 73/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0249 Epoch 74/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0256 Epoch 75/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0255 Epoch 76/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0255 Epoch 77/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0245 Epoch 78/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0247 Epoch 79/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0251 Epoch 80/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0246 Epoch 81/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0246 Epoch 82/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0248 Epoch 83/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0248 Epoch 84/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0253 Epoch 85/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0240 Epoch 86/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0240 Epoch 87/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0242 Epoch 88/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0239 Epoch 89/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0238 Epoch 90/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0246 Epoch 91/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0239 Epoch 92/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0236 Epoch 93/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0235 Epoch 94/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0242 Epoch 95/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0241 Epoch 96/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0238 Epoch 97/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0235 Epoch 98/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0240 Epoch 99/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0236 Epoch 100/100 273/273 [==============================] - 2s 8ms/step - loss: 0.0235
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.97 0.99
MAE 3646.0 2166.0
MSE 23922789.0 10149959.0
RMSE 4891.0 3186.0
MAPE 2.2 % 1.34 %
Die LSTM-Schicht wird also wieder auf 64 Neuronen reduziert. Stattdessen werden die Batches auf 16 vergrößert.
#Hyperparameter
epochs = 100
batch_size = 16
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=64, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0005)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 20000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.50 1.73 1.89 2 2.30 1.76 1.82 3 2.34 1.67 1.72 4 2.31 1.60 1.91 5 2.55 1.94 2.00 Average 2.40 1.74 1.87
Das Verhalten der Lernkurve kann durch andere Lernraten nicht verbessert werden und wird daher akzeptiert.
Durch eine Veränderung der Batch-Größe lässt sich keine Verbesserung erzielen. Die Qualität nimmt während der Kreuzvalidierungen und während des finalen Tests etwas ab. Die Verlustfunktion bleibt bei 8er Batches also nicht in einem lokalen Minimum hängen.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/100 137/137 [==============================] - 2s 4ms/step - loss: 0.1957 Epoch 2/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0920 Epoch 3/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0690 Epoch 4/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0614 Epoch 5/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0580 Epoch 6/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0546 Epoch 7/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0538 Epoch 8/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0502 Epoch 9/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0501 Epoch 10/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0492 Epoch 11/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0496 Epoch 12/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0464 Epoch 13/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0455 Epoch 14/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0453 Epoch 15/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0454 Epoch 16/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0439 Epoch 17/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0434 Epoch 18/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0428 Epoch 19/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0418 Epoch 20/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0412 Epoch 21/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0415 Epoch 22/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0410 Epoch 23/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0403 Epoch 24/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0396 Epoch 25/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0383 Epoch 26/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0381 Epoch 27/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0393 Epoch 28/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0369 Epoch 29/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0366 Epoch 30/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0367 Epoch 31/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0387 Epoch 32/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0357 Epoch 33/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0356 Epoch 34/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0353 Epoch 35/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0357 Epoch 36/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0350 Epoch 37/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0357 Epoch 38/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0344 Epoch 39/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0341 Epoch 40/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0346 Epoch 41/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0339 Epoch 42/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0346 Epoch 43/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0352 Epoch 44/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0334 Epoch 45/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0335 Epoch 46/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0340 Epoch 47/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0342 Epoch 48/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0337 Epoch 49/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0334 Epoch 50/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0327 Epoch 51/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0345 Epoch 52/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0325 Epoch 53/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0329 Epoch 54/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0324 Epoch 55/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0327 Epoch 56/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0341 Epoch 57/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0327 Epoch 58/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0319 Epoch 59/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0327 Epoch 60/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0323 Epoch 61/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0315 Epoch 62/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0315 Epoch 63/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0319 Epoch 64/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0317 Epoch 65/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0313 Epoch 66/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0307 Epoch 67/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0315 Epoch 68/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0309 Epoch 69/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0313 Epoch 70/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0310 Epoch 71/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0321 Epoch 72/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0306 Epoch 73/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0307 Epoch 74/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0308 Epoch 75/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0310 Epoch 76/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0307 Epoch 77/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0309 Epoch 78/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0305 Epoch 79/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0316 Epoch 80/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0302 Epoch 81/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0310 Epoch 82/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0305 Epoch 83/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0308 Epoch 84/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0299 Epoch 85/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0296 Epoch 86/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0295 Epoch 87/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0298 Epoch 88/100 137/137 [==============================] - 1s 5ms/step - loss: 0.0295 Epoch 89/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0294 Epoch 90/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0295 Epoch 91/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0304 Epoch 92/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0297 Epoch 93/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0295 Epoch 94/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0297 Epoch 95/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0306 Epoch 96/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0295 Epoch 97/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0286 Epoch 98/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0285 Epoch 99/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0291 Epoch 100/100 137/137 [==============================] - 1s 4ms/step - loss: 0.0289
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.96 0.98
MAE 4026.0 2686.0
MSE 28934732.0 14786249.0
RMSE 5379.0 3845.0
MAPE 2.47 % 1.67 %
Bisher wurde in allen Netzen die Tanh-Funktion zur Aktivierung verwendet, da sie vor Allem in flachen Netzen sehr gute Ergebnisse erzielt. Allerdings bietet es sich trotzdem an, die ReLu-Funktion testweise einzusetzen.
#Hyperparameter
epochs = 100
batch_size = 8
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
model.add(LSTM(units=64, return_sequences=False, activation="relu"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0005)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 20000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.37 1.38 1.62 2 2.19 1.56 1.74 3 2.13 1.40 1.59 4 2.01 1.38 1.73 5 2.32 1.41 1.67 Average 2.20 1.43 1.67
Der Einsatz der ReLu-Funktion bringt im Vergleich zu Tanh keine sonderlich großen Verbesserungen. Die Lernkurve läuft ähnlich und auch die Metriken verbessern sich nur geringfügig.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/100 273/273 [==============================] - 2s 3ms/step - loss: 0.1436 Epoch 2/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0646 Epoch 3/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0593 Epoch 4/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0538 Epoch 5/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0495 Epoch 6/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0466 Epoch 7/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0449 Epoch 8/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0447 Epoch 9/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0426 Epoch 10/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0416 Epoch 11/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0399 Epoch 12/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0403 Epoch 13/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0380 Epoch 14/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0373 Epoch 15/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0360 Epoch 16/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0353 Epoch 17/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0353 Epoch 18/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0346 Epoch 19/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0341 Epoch 20/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0334 Epoch 21/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0331 Epoch 22/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0328 Epoch 23/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0318 Epoch 24/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0323 Epoch 25/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0313 Epoch 26/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0307 Epoch 27/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0302 Epoch 28/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0302 Epoch 29/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0303 Epoch 30/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0305 Epoch 31/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0298 Epoch 32/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0304 Epoch 33/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0300 Epoch 34/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0287 Epoch 35/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0288 Epoch 36/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0280 Epoch 37/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0290 Epoch 38/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0284 Epoch 39/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0291 Epoch 40/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0290 Epoch 41/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0281 Epoch 42/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0274 Epoch 43/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0279 Epoch 44/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0272 Epoch 45/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0279 Epoch 46/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0275 Epoch 47/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0274 Epoch 48/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0278 Epoch 49/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0268 Epoch 50/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0269 Epoch 51/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0270 Epoch 52/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0271 Epoch 53/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0268 Epoch 54/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0260 Epoch 55/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0271 Epoch 56/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0260 Epoch 57/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0263 Epoch 58/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0257 Epoch 59/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0261 Epoch 60/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0257 Epoch 61/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0258 Epoch 62/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0252 Epoch 63/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0253 Epoch 64/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0257 Epoch 65/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0254 Epoch 66/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0257 Epoch 67/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0252 Epoch 68/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0250 Epoch 69/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0251 Epoch 70/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0253 Epoch 71/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0249 Epoch 72/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0247 Epoch 73/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0246 Epoch 74/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0245 Epoch 75/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0250 Epoch 76/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0245 Epoch 77/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0248 Epoch 78/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0243 Epoch 79/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0241 Epoch 80/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0243 Epoch 81/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0245 Epoch 82/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0241 Epoch 83/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0244 Epoch 84/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0245 Epoch 85/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0241 Epoch 86/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0239 Epoch 87/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0234 Epoch 88/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0240 Epoch 89/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0240 Epoch 90/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0234 Epoch 91/100 273/273 [==============================] - 1s 3ms/step - loss: 0.0234 Epoch 92/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0240 Epoch 93/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0234 Epoch 94/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0235 Epoch 95/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0230 Epoch 96/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0235 Epoch 97/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0231 Epoch 98/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0235 Epoch 99/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0232 Epoch 100/100 273/273 [==============================] - 1s 4ms/step - loss: 0.0230
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.96 0.99
MAE 3807.0 2211.0
MSE 25884008.0 10062090.0
RMSE 5088.0 3172.0
MAPE 2.3 % 1.37 %
Da sich die umfangreichen Netze leicht überanpassen, wir im Folgenden eine Regularisierung in das LSTM-6-Netz eingefügt.
#Hyperparameter
epochs = 100
batch_size = 8
window_size = 14
def model_creation():
#Modell erstellen
model = Sequential()
model.add(InputLayer(input_shape=(window_size, 4)))
regularizer = l2(0.001)
model.add(LSTM(units=64, kernel_regularizer=regularizer, return_sequences=False, activation="tanh"))
model.add(Dense(units=1))
adam = Adam(learning_rate=0.0005)
model.compile(loss=root_mean_squared_error, optimizer=adam)
return model
#Unskalierte Daten für Analysen laden
df_unscaled = pd.read_csv("../3-Data Preparation/data.csv", index_col=0, parse_dates=True)
df_unscaled.index.freq = "D"
y_test_true = df_unscaled["verbrauch"]["2021-01-01":]
y_train_true = df_unscaled["verbrauch"][window_size:2192]
#Skalierte Daten für Modellierung laden
df_scaled = pd.read_csv("../3-Data Preparation/data_scaled.csv", index_col=0, parse_dates=True)
df_scaled.index.freq = "D"
#Aufteilung X (Merkmale) und y (Ziel)
X = df_scaled[["verbrauch","arbeitstag","temperatur","tagesstunden"]]
#Stromverbrauch wird bei X um eine Stelle nach vorne verschoben, daher entfällt der 01.01.2015
X["arbeitstag"] = X["arbeitstag"].shift(-1)
X["temperatur"] = X["temperatur"].shift(-1)
X["tagesstunden"] = X["tagesstunden"].shift(-1)
X = X[:2556]
y = df_scaled["verbrauch"]
#Aufteilung der Daten in Zeitfenster
def restructure_data(px, py, window_size):
X_, y_ = [], []
idx_range = range(len(px) - (window_size) + 1)
for idx in idx_range:
X_.append(px[idx:idx+window_size])
y_.append(py[idx+window_size])
X_ = np.array(X_)
y_ = np.array(y_)
return X_, y_
X_windows, y_windows = restructure_data(X, y, window_size)
#Aufteilung in Trainings-, Validierungs- und Testdaten
split_by = 2557 - 365 - window_size
X_train = X_windows[:split_by]
y_train = y_windows[:split_by]
X_test = X_windows[split_by:]
y_test = y_windows[split_by:]
#Kreuzvalidierung erstellen
kfold = KFold(n_splits=5, shuffle=True, random_state=0)
#DataFrames für History und Metriken
df_history = pd.DataFrame()
df_history.index.name = "Epoch"
df_metrics = pd.DataFrame(columns=["Testdaten", "Trainingsdaten", "Validierungsdaten"])
df_metrics.index.name = "Split"
iteration = 1
scaler_target = joblib.load("../3-Data Preparation/scaler_endog.save")
#Kreuzvalidierung
for train_index, validation_index in kfold.split(X_train, y_train):
print(iteration, "-", end="\t")
#Modell erstellen
model = model_creation()
#Modell trainieren
history = model.fit(x=X_train[train_index], y=y_train[train_index], epochs=epochs, batch_size=batch_size, validation_data=(X_train[validation_index], y_train[validation_index]), verbose=0)
#Ergebnisse speichern
df_history[str(iteration) + "_train_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["loss"]).reshape(-1, 1)) - 102469)).squeeze()
df_history[str(iteration) + "_validation_loss"] = pd.DataFrame(data=(scaler_target.inverse_transform(np.array(history.history["val_loss"]).reshape(-1, 1)) - 102469)).squeeze()
#Vorhersagen für Test-, Trainings- und Validierungsdaten
preds_test = scaler_target.inverse_transform(model.predict(X_test).reshape(-1, 1))
preds_train = scaler_target.inverse_transform(model.predict(X_train[train_index]).reshape(-1, 1))
preds_validation = scaler_target.inverse_transform(model.predict(X_train[validation_index]).reshape(-1, 1))
df_metrics.loc[iteration] = [round(metrics.mean_absolute_percentage_error(y_test_true, preds_test) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[train_index], preds_train) * 100, 2),
round(metrics.mean_absolute_percentage_error(y_train_true[validation_index], preds_validation) * 100, 2)]
iteration = iteration + 1
#Durchschnittswerte bei History und Metriken berechnen
df_history["train_loss"] = (df_history["1_train_loss"] + df_history["2_train_loss"] + df_history["3_train_loss"] + df_history["4_train_loss"] + df_history["5_train_loss"]) / 5
df_history["validation_loss"] = (df_history["1_validation_loss"] + df_history["2_validation_loss"] + df_history["3_validation_loss"] + df_history["4_validation_loss"] + df_history["5_validation_loss"]) / 5
df_metrics.loc["Average"] = [round(df_metrics["Testdaten"].mean(), 2),
round(df_metrics["Trainingsdaten"].mean(), 2),
round(df_metrics["Validierungsdaten"].mean(), 2)]
1 - 2 - 3 - 4 - 5 -
#Training auswerten (Metriken und Lernkurve)
functions.evaluate_training(df_metrics, df_history, 20000)
Testdaten Trainingsdaten Validierungsdaten Split 1 2.28 1.61 1.75 2 2.26 1.66 1.76 3 2.47 1.66 1.70 4 2.44 1.56 1.86 5 2.11 1.73 1.82 Average 2.31 1.64 1.78
Selbst eine leichte Regularisierung führt zu einer Unteranpassung. Das Modell hat sein Potenzial zur Generalisierung also ausgeschöpft.
#Finales Modell erstellen
model = model_creation()
#Finales Modell trainieren
history = model.fit(x=X_train, y=y_train, epochs=epochs, batch_size=batch_size, use_multiprocessing=True)
Epoch 1/100 273/273 [==============================] - 3s 5ms/step - loss: 0.1444 Epoch 2/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0702 Epoch 3/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0654 Epoch 4/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0592 Epoch 5/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0577 Epoch 6/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0536 Epoch 7/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0521A: 0 Epoch 8/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0508 Epoch 9/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0493 Epoch 10/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0476 Epoch 11/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0479 Epoch 12/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0456 Epoch 13/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0452 Epoch 14/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0455 Epoch 15/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0437 Epoch 16/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0435 Epoch 17/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0423 Epoch 18/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0416 Epoch 19/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0407 Epoch 20/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0399 Epoch 21/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0403 Epoch 22/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0409 Epoch 23/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0390 Epoch 24/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0395 Epoch 25/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0386 Epoch 26/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0378 Epoch 27/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0380 Epoch 28/100 273/273 [==============================] - 2s 5ms/step - loss: 0.0379A: 0s - l Epoch 29/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0384 Epoch 30/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0380 Epoch 31/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0362 Epoch 32/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0365 Epoch 33/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0365 Epoch 34/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0360 Epoch 35/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0362 Epoch 36/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0366 Epoch 37/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0362 Epoch 38/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0357 Epoch 39/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0356 Epoch 40/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0352 Epoch 41/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0354 Epoch 42/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0349 Epoch 43/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0351 Epoch 44/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0352 Epoch 45/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0349 Epoch 46/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0349 Epoch 47/100 273/273 [==============================] - 2s 5ms/step - loss: 0.0348 Epoch 48/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0346 Epoch 49/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0349 Epoch 50/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0343 Epoch 51/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0344 Epoch 52/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0338 Epoch 53/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0332A: 0s - l Epoch 54/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0338 Epoch 55/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0336 Epoch 56/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0337 Epoch 57/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0331 Epoch 58/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0332 Epoch 59/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0337 Epoch 60/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0333 Epoch 61/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0333 Epoch 62/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0330 Epoch 63/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0326 Epoch 64/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0330 Epoch 65/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0328 Epoch 66/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0320 Epoch 67/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0318 Epoch 68/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0321 Epoch 69/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0324 Epoch 70/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0320 Epoch 71/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0320 Epoch 72/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0315 Epoch 73/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0319 Epoch 74/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0320 Epoch 75/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0319 Epoch 76/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0318 Epoch 77/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0310 Epoch 78/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0310 Epoch 79/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0314 Epoch 80/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0311 Epoch 81/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0310 Epoch 82/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0307 Epoch 83/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0310 Epoch 84/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0312 Epoch 85/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0309A: 0s - loss: Epoch 86/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0304 Epoch 87/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0301 Epoch 88/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0311 Epoch 89/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0307 Epoch 90/100 273/273 [==============================] - 2s 6ms/step - loss: 0.0301 Epoch 91/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0305 Epoch 92/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0306 Epoch 93/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0298 Epoch 94/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0300 Epoch 95/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0297 Epoch 96/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0299 Epoch 97/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0296 Epoch 98/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0297 Epoch 99/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0297 Epoch 100/100 273/273 [==============================] - 1s 5ms/step - loss: 0.0300
#Vorhersagen erzeugen
scaled_preds_test = model.predict(X_test)
scaled_preds_train = model.predict(X_train)
functions.custom_metrics_lstm(y_test_true, scaled_preds_test, y_train_true, scaled_preds_train)
Testdaten Trainingsdaten
R2 0.96 0.98
MAE 3991.0 2744.0
MSE 28029803.0 14828805.0
RMSE 5294.0 3851.0
MAPE 2.42 % 1.7 %